﻿using System;
using System.Collections.Generic;
using GeoAPI.Geometries;
using NetTopologySuite.Geometries.Implementation;
using NetTopologySuite.Geometries.Utilities;
using NetTopologySuite.Utilities;

namespace NetTopologySuite.Geometries
{
	[Serializable]
	public class GeometryFactory : IGeometryFactory
	{
		public IPrecisionModel PrecisionModel
		{
			get
			{
				return this._precisionModel;
			}
		}

		public ICoordinateSequenceFactory CoordinateSequenceFactory
		{
			get
			{
				return this._coordinateSequenceFactory;
			}
		}

		public int SRID
		{
			get
			{
				return this._srid;
			}
		}

		public static IPoint CreatePointFromInternalCoord(Coordinate coord, IGeometry exemplar)
		{
			exemplar.PrecisionModel.MakePrecise(coord);
			return exemplar.Factory.CreatePoint(coord);
		}

		public GeometryFactory(IPrecisionModel precisionModel, int srid, ICoordinateSequenceFactory coordinateSequenceFactory)
		{
			this._precisionModel = precisionModel;
			this._coordinateSequenceFactory = coordinateSequenceFactory;
			this._srid = srid;
		}

		public GeometryFactory(ICoordinateSequenceFactory coordinateSequenceFactory) : this(new PrecisionModel(), 0, coordinateSequenceFactory)
		{
		}

		public GeometryFactory(IPrecisionModel precisionModel) : this(precisionModel, 0, GeometryFactory.GetDefaultCoordinateSequenceFactory())
		{
		}

		public GeometryFactory(IPrecisionModel precisionModel, int srid) : this(precisionModel, srid, GeometryFactory.GetDefaultCoordinateSequenceFactory())
		{
		}

		public GeometryFactory() : this(new PrecisionModel(), 0)
		{
		}

		public static IPoint[] ToPointArray(ICollection<IGeometry> points)
		{
			IPoint[] array = new IPoint[points.Count];
			int num = 0;
			foreach (IGeometry geometry in points)
			{
				IPoint point = (IPoint)geometry;
				array[num++] = point;
			}
			return array;
		}

		public static IGeometry[] ToGeometryArray(ICollection<IGeometry> geometries)
		{
			IGeometry[] array = new IGeometry[geometries.Count];
			int num = 0;
			foreach (IGeometry geometry in geometries)
			{
				array[num++] = geometry;
			}
			return array;
		}

		public static ILineString[] ToLineStringArray(ICollection<IGeometry> lineStrings)
		{
			ILineString[] array = new ILineString[lineStrings.Count];
			int num = 0;
			foreach (IGeometry geometry in lineStrings)
			{
				ILineString lineString = (ILineString)geometry;
				array[num++] = lineString;
			}
			return array;
		}

		public static ILinearRing[] ToLinearRingArray(ICollection<IGeometry> linearRings)
		{
			ILinearRing[] array = new ILinearRing[linearRings.Count];
			int num = 0;
			foreach (IGeometry geometry in linearRings)
			{
				ILinearRing linearRing = (ILinearRing)geometry;
				array[num++] = linearRing;
			}
			return array;
		}

		public static IPolygon[] ToPolygonArray(ICollection<IGeometry> polygons)
		{
			IPolygon[] array = new IPolygon[polygons.Count];
			int num = 0;
			foreach (IGeometry geometry in polygons)
			{
				IPolygon polygon = (IPolygon)geometry;
				array[num++] = polygon;
			}
			return array;
		}

		public static IMultiPoint[] ToMultiPointArray(ICollection<IGeometry> multiPoints)
		{
			IMultiPoint[] array = new IMultiPoint[multiPoints.Count];
			int num = 0;
			foreach (IGeometry geometry in multiPoints)
			{
				IMultiPoint multiPoint = (IMultiPoint)geometry;
				array[num++] = multiPoint;
			}
			return array;
		}

		public static IMultiLineString[] ToMultiLineStringArray(ICollection<IGeometry> multiLineStrings)
		{
			IMultiLineString[] array = new IMultiLineString[multiLineStrings.Count];
			int num = 0;
			foreach (IGeometry geometry in multiLineStrings)
			{
				IMultiLineString multiLineString = (IMultiLineString)geometry;
				array[num++] = multiLineString;
			}
			return array;
		}

		public static IMultiPolygon[] ToMultiPolygonArray(ICollection<IGeometry> multiPolygons)
		{
			IMultiPolygon[] array = new IMultiPolygon[multiPolygons.Count];
			int num = 0;
			foreach (IGeometry geometry in multiPolygons)
			{
				IMultiPolygon multiPolygon = (IMultiPolygon)geometry;
				array[num++] = multiPolygon;
			}
			return array;
		}

		public virtual IGeometry ToGeometry(Envelope envelope)
		{
			if (envelope.IsNull)
			{
                return this.CreatePoint((ICoordinateSequence)null);
			}
			if (envelope.MinX == envelope.MaxX && envelope.MinY == envelope.MaxY)
			{
				return this.CreatePoint(new Coordinate(envelope.MinX, envelope.MinY));
			}
			if (envelope.MinX == envelope.MaxX || envelope.MinY == envelope.MaxY)
			{
				return this.CreateLineString(new Coordinate[]
				{
					new Coordinate(envelope.MinX, envelope.MinY),
					new Coordinate(envelope.MaxX, envelope.MaxY)
				});
			}
			ILinearRing shell = this.CreateLinearRing(new Coordinate[]
			{
				new Coordinate(envelope.MinX, envelope.MinY),
				new Coordinate(envelope.MinX, envelope.MaxY),
				new Coordinate(envelope.MaxX, envelope.MaxY),
				new Coordinate(envelope.MaxX, envelope.MinY),
				new Coordinate(envelope.MinX, envelope.MinY)
			});
			return this.CreatePolygon(shell, null);
		}

		public IPoint CreatePoint(Coordinate coordinate)
		{
			return this.CreatePoint((coordinate != null) ? this.CoordinateSequenceFactory.Create(new Coordinate[]
			{
				coordinate
			}) : null);
		}

		public IPoint CreatePoint(ICoordinateSequence coordinates)
		{
			return new Point(coordinates, this);
		}

		public ILineString CreateLineString(Coordinate[] coordinates)
		{
			return this.CreateLineString((coordinates != null) ? this.CoordinateSequenceFactory.Create(coordinates) : null);
		}

		public ILineString CreateLineString(ICoordinateSequence coordinates)
		{
			return new LineString(coordinates, this);
		}

		public ILinearRing CreateLinearRing(Coordinate[] coordinates)
		{
			return this.CreateLinearRing((coordinates != null) ? this.CoordinateSequenceFactory.Create(coordinates) : null);
		}

		public ILinearRing CreateLinearRing(ICoordinateSequence coordinates)
		{
			return new LinearRing(coordinates, this);
		}

		public virtual IPolygon CreatePolygon(ILinearRing shell, ILinearRing[] holes)
		{
			return new Polygon(shell, holes, this);
		}

		public virtual IPolygon CreatePolygon(ICoordinateSequence coordinates)
		{
			return this.CreatePolygon(this.CreateLinearRing(coordinates));
		}

		public virtual IPolygon CreatePolygon(Coordinate[] coordinates)
		{
			return this.CreatePolygon(this.CreateLinearRing(coordinates));
		}

		public virtual IPolygon CreatePolygon(ILinearRing shell)
		{
			return this.CreatePolygon(shell, null);
		}

		public IMultiPoint CreateMultiPoint(IPoint[] point)
		{
			return new MultiPoint(point, this);
		}

		public IMultiPoint CreateMultiPoint(Coordinate[] coordinates)
		{
			return this.CreateMultiPoint((coordinates != null) ? this.CoordinateSequenceFactory.Create(coordinates) : null);
		}

		public IMultiPoint CreateMultiPoint(ICoordinateSequence coordinates)
		{
			if (coordinates == null)
			{
				coordinates = this.CoordinateSequenceFactory.Create(new Coordinate[0]);
			}
			List<IPoint> list = new List<IPoint>();
			for (int i = 0; i < coordinates.Count; i++)
			{
				ICoordinateSequence coordinateSequence = this.CoordinateSequenceFactory.Create(1, coordinates.Ordinates);
				CoordinateSequences.Copy(coordinates, i, coordinateSequence, 0, 1);
				list.Add(this.CreatePoint(coordinateSequence));
			}
			return this.CreateMultiPoint(list.ToArray());
		}

		public IMultiLineString CreateMultiLineString(ILineString[] lineStrings)
		{
			return new MultiLineString(lineStrings, this);
		}

		public IMultiPolygon CreateMultiPolygon(IPolygon[] polygons)
		{
			return new MultiPolygon(polygons, this);
		}

		public IGeometryCollection CreateGeometryCollection(IGeometry[] geometries)
		{
			return new GeometryCollection(geometries, this);
		}

		public IGeometry BuildGeometry(ICollection<IGeometry> geomList)
		{
			Type type = null;
			bool flag = false;
			bool flag2 = false;
			IGeometry geometry = null;
			foreach (IGeometry geometry2 in geomList)
			{
				if (geometry2 != null)
				{
					geometry = geometry2;
					Type type2 = geometry2.GetType();
					if (type == null)
					{
						type = type2;
					}
					if (type2 != type)
					{
						flag = true;
					}
					if (geometry2 is IGeometryCollection)
					{
						flag2 = true;
					}
				}
			}
			if (type == null)
			{
				return this.CreateGeometryCollection(null);
			}
			if (flag || flag2)
			{
				return this.CreateGeometryCollection(GeometryFactory.ToGeometryArray(geomList));
			}
			if (geomList.Count > 1)
			{
				if (geometry is IPolygon)
				{
					return this.CreateMultiPolygon(GeometryFactory.ToPolygonArray(geomList));
				}
				if (geometry is ILineString)
				{
					return this.CreateMultiLineString(GeometryFactory.ToLineStringArray(geomList));
				}
				if (geometry is IPoint)
				{
					return this.CreateMultiPoint(GeometryFactory.ToPointArray(geomList));
				}
				Assert.ShouldNeverReachHere("Unhandled class: " + geometry.GetType().FullName);
			}
			return geometry;
		}

		public IGeometry CreateGeometry(IGeometry g)
		{
			GeometryEditor.CoordinateSequenceOperation operation = new GeometryEditor.CoordinateSequenceOperation((ICoordinateSequence x, IGeometry y) => this._coordinateSequenceFactory.Create(x));
			return new GeometryEditor(this).Edit(g, operation);
		}

		private static ICoordinateSequenceFactory GetDefaultCoordinateSequenceFactory()
		{
			return CoordinateArraySequenceFactory.Instance;
		}

		public static readonly IGeometryFactory Default = new GeometryFactory();

		public static readonly IGeometryFactory Floating = GeometryFactory.Default;

		public static readonly IGeometryFactory FloatingSingle = new GeometryFactory(new PrecisionModel(PrecisionModels.FloatingSingle));

		public static readonly IGeometryFactory Fixed = new GeometryFactory(new PrecisionModel(PrecisionModels.Fixed));

		private readonly IPrecisionModel _precisionModel;

		private readonly ICoordinateSequenceFactory _coordinateSequenceFactory;

		private readonly int _srid;
	}
}
